﻿// --------------------------------------------------------------------------------------------------------------------
// <copyright file="TaskProvider.cs" company="JaguarLabs">
//   JaguarLabs 2013
// </copyright>
// <summary>
//   Used to provide helpers methods to manage the tasks operations.
// </summary>
// --------------------------------------------------------------------------------------------------------------------

namespace TasksManagerServices.Providers
{
    using System;
    using System.Collections.Generic;
    using System.Data.Linq;
    using System.Linq;
    using TasksManagerServices.Data;
    using dto = TasksManagerServices.ValueObjects;

    public static class TaskProvider
    {
        /// <summary>
        /// Gets the user tasks.
        /// </summary>
        /// <param name="user">The user.</param>
        /// <returns></returns>
        public static IEnumerable<dto.Task> GetUserTasks(string user)
        {
            try
            {
                var tasks = new List<dto.Task>();
                using (var context = new TaskManagementDBDataContext())
                {
                    tasks = context.UserTasks
                                   .Where(task => task.Usr == user)
                                   .Select(userTask => new dto.Task
                                       {
                                           Id = userTask.Task.Id,
                                           Name = userTask.Task.Name,
                                           Attachments = userTask.Task.Attachments.Select(
                                               attachment => new dto.Attachment
                                                   {
                                                       Id = attachment.Id,
                                                       Name = attachment.Name,
                                                       Link = attachment.Link
                                                   }).ToList(),
                                           EndDate = userTask.Task.EndDate,
                                           NotificationDate = userTask.Task.Notification,
                                           Description = userTask.Task.Description,
                                           Notified = userTask.Task.Notified,
                                           ShowInCalendar = userTask.Task.ShowInCalendar,
                                           Progress = userTask.Task.Progress ?? 0,
                                           PriorityId = userTask.Task.PriorityId,
                                           ProjectId = userTask.Task.Project.Id,
                                           ProjectName = userTask.Task.Project.Name
                                       }
                        ).ToList();

                    // Priority name.
                    // TODO: fix the relation between tables, for some reason is not in the dbml.
                    tasks.ForEach(
                        t => t.PriorityName = context.Priorities.Single(p => p.Id == t.PriorityId).Name);
                }

                return tasks;
            }
            catch (Exception ex)
            {
                throw new Exception(string.Format("DB Error: {0}", ex.Message));
            }
        }

        /// <summary>
        /// Inserts the task.
        /// </summary>
        /// <param name="task">The task.</param>
        /// <returns></returns>
        /// <exception cref="System.Exception">
        /// </exception>
        public static int InsertTask(dto.Task task)
        {
            try
            {
                var newTaskId = 0;

                // Validate task entries.
                var errorMeesage = ValidateTask(task);
                if (!string.IsNullOrEmpty(errorMeesage))
                {
                    throw new Exception(errorMeesage);
                }

                using (var context = new TaskManagementDBDataContext())
                {
                    // Inserting task.
                    var newTask = new Task
                        {
                            Name = task.Name,
                            Description = task.Description,
                            EndDate = task.EndDate,
                            PriorityId = task.PriorityId,
                            Notification = task.NotificationDate,
                            ProjectId = task.ProjectId,
                            Progress = task.Progress,
                            ShowInCalendar = task.ShowInCalendar,
                            Notified = task.Notified
                        };
                    context.Tasks.InsertOnSubmit(newTask);
                    context.SubmitChanges(ConflictMode.FailOnFirstConflict);

                    // Inserting attachments.
                    if (task.Attachments.Any())
                    {
                        context.Attachments.InsertAllOnSubmit(task.Attachments
                                                                  .Select(attachment => new Attachment
                                                                      {
                                                                          Link = attachment.Link,
                                                                          Name = attachment.Name,
                                                                          TaskId = newTask.Id
                                                                      }));
                    }

                    // Inserting assignations.
                    if (task.Users.Any())
                    {
                        context.UserTasks.InsertAllOnSubmit(task.Users
                                                                .Select(user => new UserTask()
                                                                    {
                                                                        TaskId = newTask.Id,
                                                                        Usr = user
                                                                    }));
                    }

                    // Saving changes.
                    context.SubmitChanges(ConflictMode.FailOnFirstConflict);
                    newTaskId = newTask.Id;
                }


                return newTaskId;
            }
            catch (Exception ex)
            {
                throw new Exception(string.Format("DB Error: {0}", ex.Message));
            }
        }

        /// <summary>
        /// Updates the task.
        /// </summary>
        /// <param name="task">The task.</param>
        /// <returns></returns>
        /// <exception cref="System.Exception">
        /// Error al actualizar: La tarea no existe.
        /// or
        /// Error al actualizar: La tarea no existe.
        /// or
        /// </exception>
        public static bool UpdateTask(dto.Task task)
        {
            try
            {
                var updated = false;

                // Validate task entries.
                var errorMeesage = ValidateTask(task);
                if (!string.IsNullOrEmpty(errorMeesage))
                {
                    throw new Exception(errorMeesage);
                }

                using (var context = new TaskManagementDBDataContext())
                {
                    // Validate task existence.
                    var tasksToUpdate = context.Tasks.Where(t => t.Id == task.Id);
                    if (!tasksToUpdate.Any())
                    {
                        throw new Exception("Error al actualizar: La tarea no existe.");
                    }

                    var taskToUpdate = tasksToUpdate.FirstOrDefault();
                    if (taskToUpdate == null)
                    {
                        throw new Exception("Error al actualizar: La tarea no existe.");
                    }

                    // Updating task properties.
                    taskToUpdate.Name = task.Name;
                    taskToUpdate.Description = task.Description;
                    taskToUpdate.EndDate = task.EndDate;
                    taskToUpdate.PriorityId = task.PriorityId;
                    taskToUpdate.Notification = task.NotificationDate;
                    taskToUpdate.ProjectId = task.ProjectId;
                    taskToUpdate.Progress = task.Progress;
                    taskToUpdate.ShowInCalendar = task.ShowInCalendar;
                    taskToUpdate.Notified = task.Notified;

                    // Updating assignations.
                    context.UserTasks.DeleteAllOnSubmit(
                        context.UserTasks.Where(userTask => userTask.TaskId == task.Id));
                    if (task.Users.Any())
                    {
                        context.UserTasks.InsertAllOnSubmit(task.Users
                                                                .Select(user => new UserTask()
                                                                {
                                                                    TaskId = task.Id,
                                                                    Usr = user
                                                                }));
                    }

                    // Updating attachments.
                    context.Attachments.DeleteAllOnSubmit(
                        context.Attachments.Where(attachment => attachment.TaskId == task.Id));
                    if (task.Attachments.Any())
                    {
                        context.Attachments.InsertAllOnSubmit(task.Attachments
                                                                  .Select(attachment => new Attachment
                                                                  {
                                                                      Link = attachment.Link,
                                                                      Name = attachment.Name,
                                                                      TaskId = task.Id
                                                                  }));
                    }

                    // Saving changes.
                    context.SubmitChanges(ConflictMode.FailOnFirstConflict);
                }

                return true;
            }
            catch (Exception ex)
            {
                throw new Exception(string.Format("DB Error: {0}", ex.Message));
            }
        }

        /// <summary>
        /// Deletes the task.
        /// </summary>
        /// <param name="id">The id.</param>
        /// <returns></returns>
        /// <exception cref="System.Exception">
        /// Error al eliminar: El parámetro id no es válido.
        /// or
        /// Error al eliminar: La tarea no existe.
        /// or
        /// Error al eliminar: La tarea no existe.
        /// or
        /// </exception>
        public static bool DeleteTask(int id)
        {
            try
            {
                if (id < 0)
                {
                    throw new Exception("Error al eliminar: El parámetro id no es válido.");
                }

                using (var context = new TaskManagementDBDataContext())
                {
                    // Deleting attachments.
                    var attachmentsToDelete = context.Attachments.Where(t => t.TaskId == id);
                    context.Attachments.DeleteAllOnSubmit(attachmentsToDelete);

                    // Deleting assignations.
                    var usertasksToDelete = context.UserTasks.Where(t => t.TaskId == id);
                    context.UserTasks.DeleteAllOnSubmit(usertasksToDelete);

                    // Deleting task.
                    var tasksToDelete = context.Tasks.Where(t => t.Id == id);
                    if (!tasksToDelete.Any())
                    {
                        throw new Exception("Error al eliminar: La tarea no existe.");
                    }

                    var taskToDelete = tasksToDelete.FirstOrDefault();
                    if (taskToDelete == null)
                    {
                        throw new Exception("Error al eliminar: La tarea no existe.");
                    }
                    
                    context.Tasks.DeleteOnSubmit(taskToDelete);

                    // Saving changes.
                    context.SubmitChanges(ConflictMode.FailOnFirstConflict);
                }

                return true;

            }
            catch (Exception ex)
            {
                throw new Exception(string.Format("DB Error: {0}", ex.Message));
            }
        }

        /// <summary>
        /// Validates the task.
        /// </summary>
        /// <param name="task">The task.</param>
        /// <returns></returns>
        private static string ValidateTask(dto.Task task)
        {
            if (task == null)
            {
                return "El parámetro: Tarea no puede ser nulo.";
            }
            else
            {
                if (string.IsNullOrEmpty(task.Name))
                {
                    return "El parámetro: Nombre no puede ser nulo.";
                }

                if (string.IsNullOrEmpty(task.Description))
                {
                    return "El parámetro: Descripción no puede ser nulo.";
                }

                if (task.Users == null || !task.Users.Any())
                {
                    return "El parámetro: Usuarios no puede ser nulo.";
                }

                using (var context = new TaskManagementDBDataContext())
                {
                    if (!context.Priorities.Any(p => p.Id == task.PriorityId))
                    {
                        return "La prioridad no es válida.";
                    }

                    if (!context.Projects.Any(p => p.Id == task.ProjectId))
                    {
                        return "El proyecto no es valido.";
                    }
                }
            }

            return null;
        }

        /// <summary>
        /// Gets the projects.
        /// </summary>
        /// <returns></returns>
        public static IEnumerable<dto.Project> GetProjects()
        {
            try
            {
                var projects = new List<dto.Project>();
                using (var context = new TaskManagementDBDataContext())
                {
                    projects = context.Projects
                                      .Select(project => new dto.Project()
                                          {
                                              Id = project.Id,
                                              Name = project.Name,
                                          }
                        ).ToList();
                }

                return projects;
            }
            catch (Exception ex)
            {
                throw new Exception(string.Format("DB Error: {0}", ex.Message));
            }
        }
    }
}
